package xyz.erupt.flow.core.engine.service.Impl;

import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.impl.batch.history.HistoricBatchEntity;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ActivityInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.Activity;
import org.camunda.bpm.model.xml.instance.DomElement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.erupt.core.exception.EruptApiErrorTip;
import xyz.erupt.flow.bean.entity.OaHistoryTaskEx;
import xyz.erupt.flow.bean.entity.OaWorkFlowDefinition;
import xyz.erupt.flow.bean.entity.node.OaProcessNode;
import xyz.erupt.flow.bean.entity.node.OaProcessNodeProps;
import xyz.erupt.flow.bean.entity.node.OaProcessNodeRefuse;
import xyz.erupt.flow.constant.FlowConstant;
import xyz.erupt.flow.core.engine.service.WorkFlowRefusePolicyService;
import xyz.erupt.flow.repository.OaHistoryTaskExRepository;
import xyz.erupt.flow.service.WorkFlowDefinitionService;
import xyz.erupt.flow.utils.WorkFlowUtils;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author PP
 * @version 1.0
 * @project flow
 * @description 策略实现
 * @date 2024/11/5 17:27:51
 */
@Service
public class WorkFlowRefusePolicyServiceImpl implements WorkFlowRefusePolicyService {
    @Autowired
    private WorkFlowDefinitionService workFlowDefinitionService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private OaHistoryTaskExRepository historyTaskExRepository;

    /**
     * 根据策略进行拒绝
     * @param taskId
     */
    @Override
    public void refuse(String taskId, String reason){
        //获取流程定义节点数据
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .active()
                .singleResult();
        if (task == null) {
            throw new EruptApiErrorTip(String.format("任务不存在:taskId:%s",taskId));
        }
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId())
                .singleResult();
        OaWorkFlowDefinition definition = workFlowDefinitionService.getById(WorkFlowUtils.keyToWorkFlowDefinitionId(processDefinition.getKey()));
        OaProcessNode processNode = definition.getProcessNode();
        OaProcessNode node = processNode.findNodeById(task.getTaskDefinitionKey());
        if (node == null) {
            throw new EruptApiErrorTip(String.format("流程不存在节点:node_id:%s",task.getTaskDefinitionKey()));
        }
        //根据配置进行拒绝
        OaProcessNodeProps props = node.getProps();
        OaProcessNodeRefuse refuse = props.getRefuse();
        ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());//获取活动实例
        if(FlowConstant.REFUSE_TO_END.equals(refuse.getType())){//拒绝结束流程
            runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
                    .cancelActivityInstance(activityInstance.getId())//取消流程
                    .setAnnotation(reason)//注入原因
                    .startBeforeActivity("end")//直接结束
                    .execute();
        } else if (FlowConstant.REFUSE_TO_BEFORE.equals(refuse.getType())) {//拒绝返回上级节点
            String targetId = processNode.findSuperNodeById(task.getTaskDefinitionKey());//查找上级节点（连线/节点）
            HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()//查找目标节点的活动实例
                    .activityId(targetId).processInstanceId(task.getProcessInstanceId())
                    .orderByHistoricActivityInstanceStartTime()
                    .desc().list().get(0);
            List<HistoricVariableInstance> list;
            if (historicActivityInstance!=null){
                list  = historyService.createHistoricVariableInstanceQuery()
                        .processInstanceId(task.getProcessInstanceId())
                        .activityInstanceIdIn(historicActivityInstance.getId())
                        .list();
            }else {
                list = null;
            }
            Map<String, Object> map;
            if (list!=null && list.size()>0) {
                map=list.stream().collect(HashMap::new,(mapc,item)->mapc.put(item.getName(),item.getValue()),(map1,map2)->map1.putAll(map2));
            }else {
                map = new HashMap<>();
            }
            runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
                    .cancelActivityInstance(activityInstance.getId())//取消流程
                    .setAnnotation(reason)//注入原因
                    .startBeforeActivity(targetId)//跳反上级
                    .setVariables(map)
                    .execute();

        } else if (FlowConstant.REFUSE_TO_NODE.equals(refuse.getType())) {//拒绝跳转指定节点
            String targetId = processNode.gotoNodeById(refuse.getTarget());//查询跳转节点的目标节点id（连线/节点）
            HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()//查找目标节点的活动实例
                    .activityId(targetId).processInstanceId(task.getProcessInstanceId())
                    .orderByHistoricActivityInstanceStartTime()
                    .desc().list().get(0);
            List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .activityInstanceIdIn(historicActivityInstance.getId())
                    .list();
            Map<String, Object> map;
            if (list!=null && list.size()>0) {
                map=list.stream().collect(HashMap::new,(mapc,item)->mapc.put(item.getName(),item.getValue()),(map1,map2)->map1.putAll(map2));
            }else {
                map = new HashMap<>();
            }
            runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
                    .cancelActivityInstance(activityInstance.getId())//取消流程
                    .setAnnotation(reason)//注入原因
                    .startBeforeActivity(targetId)//跳反指定节点
                    .setVariables(map)
                    .execute();
        }
        //储存历史任务拓展数据
        OaHistoryTaskEx build = OaHistoryTaskEx.builder().taskId(taskId).remark(reason).build();
        historyTaskExRepository.save(build);

    }



    /**
     * 判断一个节点是否为多实例节点
     *
     * @param execution 监听器 DelegateExecution 对象
     * @param activityId 节点Id
     * @return 是否多实例节点
     */
    public boolean isMultiInstanceActivity(DelegateExecution execution, String activityId){
        Activity activity = execution.getBpmnModelInstance().getModelElementById(activityId);
        return activity.getLoopCharacteristics() != null;
    }

    /**
     * 查找前一个用户任务
     * @param currentActivityId
     * @return
     */
    private String findBeforeUserNodeByCurrentTask(String currentActivityId,String processInstanceId) {
        //新建一个有序不重复集合
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet();
        String backTask = "";
        //获取当前任务节点
        historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceEndTime().asc().list()
                .stream().forEach(historicTaskInstance -> {
                    linkedHashSet.add(historicTaskInstance.getTaskDefinitionKey());
                });
        if(linkedHashSet.size() == 0){
            return backTask;
        }
        //遍历到当前任务的任务节点后，取上一次遍历的值
        Iterator iterator = linkedHashSet.iterator();
        while (iterator.hasNext()) {
            String nowTask = iterator.next().toString();
            if(nowTask.equals(currentActivityId)){
                return backTask;
            }
            backTask = nowTask;
        }
        return backTask;
    }

}
